Fix frameclock going backwards
authorAlexander Larsson <alexl@redhat.com>
Mon, 1 Jun 2020 08:53:24 +0000 (10:53 +0200)
committerAlexander Larsson <alexl@redhat.com>
Mon, 1 Jun 2020 08:53:24 +0000 (10:53 +0200)
When we run the frameclock RUN_FLUSH_IDLE idle before the paint,
then gdk_frame_clock_flush_idle() sets
```
  priv->phase = GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT
```
at the end if there is a paint comming.

But, before doing the paint cycle it may handle other X events, and
during that time the phase is set to BEFORE_PAINT. This means that the
current check on whether we're inside a paint is wrong:

```
  if (priv->phase != GDK_FRAME_CLOCK_PHASE_NONE &&
     priv->phase != GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS)
    return priv->smoothed_frame_time_base;
```

This caused us to sometimes use this smoothed_frame_time_base even
though we previously reported a later value during PHASE_NONE, thus
being non-monotonic.

We can't just additionally check for the BEGIN_PAINT phase though,
becasue if we are in the paint loop actually doing that phase we
should use the time base. Instead we check for `!(BEFORE_PAINT &&
in_paint_idle)`.

gdk/gdkframeclockidle.c

index bbb4e2d26e294c60ef1de499514b22b246dfe59d..ef32ad518a75b15d415a87bbf43227a7827d87b2 100644 (file)
@@ -236,7 +236,8 @@ gdk_frame_clock_idle_get_frame_time (GdkFrameClock *clock)
 
   /* can't change frame time during a paint */
   if (priv->phase != GDK_FRAME_CLOCK_PHASE_NONE &&
-      priv->phase != GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS)
+      priv->phase != GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS &&
+      (priv->phase != GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT || priv->in_paint_idle))
     return priv->smoothed_frame_time_base;
 
   /* Outside a paint, pick something smoothed close to now */